#include "windowX.h"

namespace WINDX
{
	WinEX::WinEX(std::string Title, SIZE sZ, POINT PT)
	{
		InitWin(Title, sZ, PT);
	}
	WinEX::WinEX(std::string Title, SIZE sZ)
	{
		POINT PT = { CW_USEDEFAULT, CW_USEDEFAULT };
		InitWin(Title, sZ, PT);
	}
	WinEX::WinEX(std::string Title)
	{
		SIZE sZ = { 800, 600 };
		POINT PT = { CW_USEDEFAULT, CW_USEDEFAULT };
		InitWin(Title, sZ, PT);
	}

	void WinEX::InitWin(std::string Windowname, SIZE sz, POINT pt)
	{
		memset(&wndclass, 0, sizeof(wndclass));
		hInstance = GetModuleHandle(nullptr);
		sprintf(mp_Class, "0x%p", this);
			
		wndclass.cbSize = sizeof(wndclass);
		wndclass.style = CS_HREDRAW | CS_VREDRAW ;
		wndclass.lpfnWndProc = &WINDX::WinEX::WndHandle;
		wndclass.cbClsExtra = 0;
		wndclass.cbWndExtra = 0;
		wndclass.hInstance = hInstance;
		wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
		wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
		wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
		wndclass.lpszClassName = mp_Class;

		if(!RegisterClassEx(&wndclass))
		{
			MessageBoxA(NULL, 
						TEXT("Error: Klasse konnte nicht erstellt werden."),
						NULL,
						MB_OK | MB_ICONERROR);
			ExitProcess(0);
		}

		hwnd = CreateWindow(mp_Class, 
							Windowname.c_str(), 
							WS_OVERLAPPEDWINDOW,
							pt.x,
							pt.y,
							sz.cx,
							sz.cy,
							NULL,
							NULL,
							hInstance,
							NULL);
	}

	void WinEX::InitDX()
	{
		g_d3d = Direct3DCreate9(D3D_SDK_VERSION);

		D3DPRESENT_PARAMETERS params;
		memset(&params, 0, sizeof(params));
		params.BackBufferFormat = D3DFMT_X8R8G8B8;
		params.AutoDepthStencilFormat = D3DFMT_D24S8;
		if(!IsDepthFormatOk(params.AutoDepthStencilFormat, params.BackBufferFormat, params.BackBufferFormat)) //u wonder y i use BackBufferFormat for adapter, cause it's the same
		{
			MessageBoxA(NULL, TEXT("Error: Some failure in the BackBuffer acursed."), NULL, MB_OK | MB_ICONERROR);
			ExitProcess(0);
		}
		params.BackBufferHeight = GetWindowSize().cy;
		params.BackBufferWidth = GetWindowSize().cx;
		params.EnableAutoDepthStencil = true;
		params.hDeviceWindow = GetHWND();
		params.SwapEffect = D3DSWAPEFFECT_DISCARD;
		params.Windowed = true;

		HRESULT hr = g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetHWND(), D3DCREATE_HARDWARE_VERTEXPROCESSING, &params, &g_d3dDevice);
		if(FAILED(hr))
		{
			MessageBoxA(NULL, DXGetErrorString(hr), NULL, MB_OK | MB_ICONERROR);
			ExitProcess(0);
		}

		//Start Init
		m_tria = new Geometry::Triangle(100, 100, 200, 200);
		//End Init

		D3DXMATRIX matProj;
		D3DXMatrixPerspectiveFovLH(&matProj, D3DXToRadian(45.0f), (float)GetWindowSize().cx / GetWindowSize().cy, 1.0f, 10000.0f);
		g_d3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);

		D3DXMATRIX matView;
		D3DXVECTOR3 vEye(600.0f, 50.0f, 600.0f), vTarget(0.0f, 50.0f, 0.0f), vUp(0.0f, 1.0f, 0.0f);
		D3DXMatrixLookAtLH(&matView, &vEye, &vTarget, &vUp);
		g_d3dDevice->SetTransform(D3DTS_VIEW, &matView);

		g_d3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
		g_d3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	}

	LRESULT CALLBACK WinEX::WndHandle(HWND hwnd, UINT uint, WPARAM wparam, LPARAM lparam)
	{
		switch (uint)
		{
		case WM_CREATE:
			break;
		case WM_CLOSE:
			PostQuitMessage(0);
			break;
		}

		return DefWindowProc(hwnd, uint, wparam, lparam);
	};

	void WinEX::Render()
	{
		g_d3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET, D3DCOLOR_ARGB(0xFF, 135, 206, 255), 1.0f, 0);
		g_d3dDevice->BeginScene();

		g_d3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		g_d3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		g_d3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		//Start Renders
		m_tria->DrawTriangle(g_d3dDevice);
		//End Renders

		g_d3dDevice->EndScene();
		g_d3dDevice->Present(NULL, NULL, NULL, NULL);
	}

	BOOL WinEX::RunWin() 
	{
		if(!hwnd)
			return false;
		ShowWindow(hwnd, SW_SHOW);
		isrunning = true;
		do
		{
			while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			Render();
			Sleep(10);
		} while (isrunning);

		return true;
	};
}